import { TreeSelect, TreeSelectProps } from 'antd';
import { FC, useMemo, useState } from 'react';

import { arrayToNestJson } from '@ey-utils/utils/utils';

import warning from 'warning';
import { merge } from 'lodash';
import { getTempData } from '@/biz-components/_common/wrapXhr';
import { DynamicObjectAny } from '@/typings';
import { isValueEqual, transformValue } from '@/biz-components/_common/util';

const { SHOW_ALL } = TreeSelect;

interface AsyncTreeSelectProps<T = any> extends TreeSelectProps<T> {
  disabledTypes?: string[];
  checkableTypes?: string[];
  childParams?: DynamicObjectAny;
  parentKey?: string;
  idKey?: string;
  api: ApiConfig;
  editable?: boolean;
  selectableCb?: (node: any) => boolean;
  changeKey?: string;
  extraData?: treeDataItem[];
}

interface treeDataItem {
  title?: string;
  value: string;
  pId?: string;
  [key: string]: any;
}

const AsyncTreeSelect: FC<AsyncTreeSelectProps> = ({
  disabledTypes,
  childParams,
  parentKey,
  checkableTypes,
  api,
  editable,
  value,
  idKey = 'id',
  selectableCb,
  onChange,
  changeKey,
  extraData,
  ...restProps
}) => {
  if (!editable) {
    return <span>{value}</span>;
  }

  const [loading, setLoading] = useState(false);

  const { params, url, method } = api || {};

  warning(!(method && url), '请配置 api 下的 url method');

  const [treeData, setTreeData] = useState<treeDataItem[]>([]);

  const updateTreeData = (result: any[], parentId: string) => {
    setTreeData((data) => {
      const newData = result?.map((item) => {
        const { name, code, type } = item;

        let disabled = false;

        if (disabledTypes?.length) {
          disabled = disabledTypes.includes(type);
        }

        if (checkableTypes?.length) {
          disabled = !checkableTypes.includes(type);
        }
        if (selectableCb) {
          disabled = selectableCb(item);
        }

        return {
          pId: parentId,
          title: name,
          value: code,
          disabled,
          ...item,
        };
      });

      return data.concat(newData);
    });
  };

  const search = () => {
    setLoading(true);
    getTempData({
      url,
      params,
      type: method,
    })
      .then((res: any) => {
        updateTreeData(res, '0');
      })
      .finally(() => {
        setLoading(false);
      });
  };

  const handleChange = (value: any, label: any, extra: any) => {
    const newValue = Array.isArray(value)
      ? value.map((item) => {
          return transformValue(item, changeKey);
        })
      : transformValue(value, changeKey);

    onChange?.(newValue, label, extra);
  };

  const handleFocus = () => {
    if (treeData.length === 0) {
      search();
    }
  };

  const loadData = (treeNode: any) => {
    const parentKeyPath = parentKey?.split('.') || [];

    warning(!parentKeyPath.length, `${parentKey} 非字符串或者是空字符串无法设置搜索请设置`);

    return getTempData({
      type: method,
      params: merge(arrayToNestJson(parentKeyPath, treeNode.props[idKey]), childParams),
      url,
    }).then((res: any) => {
      updateTreeData(res, treeNode.props.id);
    });
  };

  const displayValue = useMemo(() => {
    const data = treeData.concat(extraData || []);

    if (Array.isArray(value)) {
      return value.map((val: any) => {
        const record = data.find((item) =>
          isValueEqual(transformValue(item, changeKey), transformValue(val, changeKey)),
        );
        return record || val;
      });
    }
    return data.find((item) =>
      isValueEqual(transformValue(item, changeKey), transformValue(value, changeKey)),
    );
  }, [extraData, value, treeData]);

  return (
    <TreeSelect
      treeDataSimpleMode
      treeCheckStrictly
      showCheckedStrategy={SHOW_ALL}
      value={displayValue}
      {...restProps}
      onChange={handleChange}
      style={{
        width: '100%',
      }}
      loading={loading}
      treeData={treeData}
      loadData={loadData}
      dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
      onFocus={handleFocus}
    />
  );
};

AsyncTreeSelect.defaultProps = {
  idKey: 'id',
  disabledTypes: [],
  editable: true,
  placeholder: '请选择角色',
};

export default AsyncTreeSelect;
